7장. 모델을 살짝 더 가르치기

출처: 『AI 엔지니어링』(Chip Huyen 지음) | 원서: AI Engineering (O'Reilly) — 본 입문판은 PDF 원문(7장)에서 직접 풀어 썼다.

코드는 분위기만 — Python·메모리 계산 같은 말은 몰라도 됩니다. 표의 '비유'와 '위험'만 봐도 충분해요.

이 장은 0장 용어집을 안다고 가정한다.

막히면 0장으로 돌아가면 된다.


0. 이 장의 새 단어 (0장에 없는 것만)

이 장에서 처음 나오는 어려운 말은 딱 3개다.

나머지 어려운 말은 전부 0장 용어집에 있다.


메모리(memory, 여기선 GPU 메모리)

한 문장 뜻 — 모델을 학습시키거나 돌릴 때, 계산에 필요한 숫자들을 잠깐 올려두는 작업 공간.

일상비유 — 요리할 때 도마 위 공간. 도마가 작으면 재료를 다 못 올려서 요리를 시작조차 못 한다.

한 줄 예 —

# 아래 예제는 핵심 흐름만 짧게 보여 줍니다.
# 모델이 너무 크면 도마(메모리)에 안 올라가서 멈춤
model.load()  # → "메모리 부족" 에러

파라미터 효율적 파인튜닝(PEFT, parameter-efficient fine-tuning)

한 문장 뜻 — 모델 전체가 아니라 아주 일부 손잡이만 돌려서, 적은 메모리로 파인튜닝하는 방법.

일상비유 — 옷 전체를 다시 짜지 않고 소매 길이만 줄이는 수선. 결과는 비슷한데 품이 훨씬 적게 든다.

한 줄 예 —

# 아래 예제는 핵심 흐름만 짧게 보여 줍니다.
# 손잡이 1,000억 개 중 극히 일부만 돌림
model.finetune(data, method="LoRA")  # 메모리 적게 듦

양자화(quantization)

한 문장 뜻 — 숫자 하나를 표현하는 데 쓰는 자릿수를 줄여, 모델이 차지하는 공간을 줄이는 것.

일상비유 — 3.141592를 3.14로 반올림해 적기. 정확도는 살짝 떨어지지만 적는 칸이 확 줄어든다.

한 줄 예 —

# 아래 예제는 핵심 흐름만 짧게 보여 줍니다.
# 숫자 1개당 4칸 → 1칸으로 줄이면 모델 크기도 줄어듦
load_model(bits=4)  # 메모리 절반 이하

(귀납 도입) 이런 적 있죠?

회사에서 챗봇을 만들었다.

대부분 질문엔 잘 답하는데, 우리 회사만의 특이한 SQL 문법은 자꾸 틀린다.

프롬프트를 아무리 고쳐도 안 된다.

이럴 때 모델 자체를 "우리 데이터로 며칠 더 가르치는" 방법이 있다.

그게 파인튜닝이다 (0장 용어집 참고).

말로 시키는 게 프롬프트라면, 파인튜닝은 모델 안의 손잡이를 직접 돌려 버릇을 바꾸는 것이다.

# 아래 예제는 핵심 흐름만 짧게 보여 줍니다.
# 프롬프트: 모델은 그대로, 말만 바꿈
model.ask("우리 SQL 문법으로 짜줘")  # 자꾸 틀림

# 파인튜닝: 모델 안을 바꿈
model.finetune(our_sql_examples)  # 버릇을 새로 들임

문제는 이게 공짜가 아니라는 점이다.

손잡이를 돌리려면 거대한 작업 공간(메모리)이 필요하다.

그래서 이 장의 절반은 "어떻게 적은 공간으로 가르치나"에 대한 이야기다.


이 장에서 딱 4가지만

TL;DR

  1. 언제 파인튜닝하나 — 모델이 사실을 몰라서 틀리면 RAG, 버릇·형식이 틀리면 파인튜닝.
  2. 왜 어렵나 — 파인튜닝은 작업 공간(메모리)을 엄청나게 잡아먹는다. 이게 가장 큰 벽.
  3. 공간 줄이는 법 1 — 숫자 자릿수를 줄인다(양자화).
  4. 공간 줄이는 법 2 — 손잡이를 다 안 돌리고 일부만 돌린다(PEFT·LoRA).

개념 1 — RAG냐 파인튜닝이냐: 오류 원인이 정한다

망가지는 장면

"모델이 자꾸 틀려. 그냥 파인튜닝하자."

이렇게 무작정 파인튜닝하면 돈·시간만 쓰고 효과가 없을 때가 많다.

먼저 물어야 할 건 "왜 틀렸나"다.

일상비유

학생이 시험을 틀렸다.

자료를 몰라서 틀렸으면 → 자료를 펼쳐 주면 된다(오픈북 = RAG).

아는데 답안 형식을 안 지켜서 틀렸으면 → 답안 쓰는 법을 다시 가르쳐야 한다(재교육 = 파인튜닝).

원인이 다르면 처방도 다르다.

비유 코드 위험
자료를 몰라서 틀림 → 오픈북(RAG) model.ask(q, context=docs) 자료를 안 붙이면 지어냄(환각)
형식·버릇이 틀림 → 재교육(파인튜닝) model.finetune(format_examples) 한 작업 고치면 다른 작업이 나빠질 수 있음

한 문장 정의 — 모델이 정보가 부족해 틀리면 RAG, 모델의 행동 방식(형식·스타일)이 틀리면 파인튜닝이다.

단순 규칙: 파인튜닝은 형식을 위한 것, RAG는 사실을 위한 것.

원서의 한 줄 요약이 이거다.

외워 두면 절반은 끝난다.

예시 1 — 정보가 부족한 경우 (worked example, 완성 예)

질문: "테일러 스위프트는 정규 앨범을 몇 개 냈나요?"

모델: "10개입니다."

정답: 11개.

왜 틀렸나? 모델이 학습한 시점 이후에 새 앨범이 나왔기 때문이다.

이건 정보 부족이다 → RAG로 최신 자료를 붙여 주면 해결된다.

# 최신 자료를 찾아 붙여 줌
# 질문과 가까운 문서 조각을 찾아오는 검색 단계를 실행합니다.
docs = search("테일러 스위프트 최신 앨범")
model.ask("정규 앨범 몇 개?", context=docs)  # → 11개

예시 2 — 행동 방식이 문제인 경우 (부분 완성, 빈칸 채우기)

상황: 모델에게 HTML 코드를 짜 달라고 했는데, 만든 코드가 안 돌아간다.

이건 정보 부족이 아니다. HTML이라는 형식을 제대로 못 따르는 것이다.

따라서 처방은 ____ 이다.

(빈칸 답: 파인튜닝. HTML 예시를 더 학습시킨다.)

예시 3 — 둘 다 문제일 때 (독립 적용)

회사 문서 챗봇이 (a) 사내 규정을 모르고 (b) 답변 말투도 딱딱하다.

당신이라면 무엇부터?

권장 순서는 RAG 먼저다.

RAG는 학습 데이터를 안 모아도 되고 별도 모델을 안 굴려도 돼서 더 쉽다.

규정 문제(사실)를 RAG로 풀고, 말투 문제(형식)가 남으면 그때 파인튜닝한다.

미니 시나리오 — 개발 순서 (원서 권장)

  1. 먼저 프롬프트를 제대로 다듬는다.
  2. 안 되면 프롬프트에 예시 몇 개를 넣어 본다.
  3. 정보가 부족하면 간단한 RAG(키워드 검색)부터 붙인다.
  4. 그래도 정보 오류면 더 좋은 RAG, 행동 문제면 파인튜닝.
  5. 더 욕심나면 RAG와 파인튜닝을 함께 쓴다.

한 걸음 더 ▸ (지금 몰라도 됨)

한 연구(Ovadia et al., 2024)에서 재미있는 결과가 나왔다. 시사 질문에서는 파인튜닝한 모델보다, 안 건드린 기본 모델에 RAG만 붙인 쪽이 더 잘했다. 파인튜닝이 만능이 아니라는 뜻이다. 지금은 "사실은 RAG, 형식은 파인튜닝"만 기억하면 된다.


개념 2 — 메모리 병목: 파인튜닝이 어려운 진짜 이유

망가지는 장면

"파인튜닝 코드를 돌렸더니 'CUDA out of memory'(메모리 부족) 에러가 떴다."

모델이 너무 커서 작업 공간에 안 들어간 것이다.

일상비유

요리할 때 도마가 작으면 재료를 다 못 올린다.

큰 모델은 재료(숫자)가 너무 많아, 웬만한 도마(GPU)에는 안 올라간다.

그리고 중요한 점 하나.

그냥 모델을 돌리는 것(추론)보다 모델을 가르치는 것(학습)이 도마를 훨씬 더 많이 잡아먹는다.

비유 코드 위험
음식 데우기만(추론) model.ask(q) → 도마 조금 그래도 큰 모델은 부족할 수 있음
재료 손질+요리(학습) model.finetune(data) → 도마 훨씬 많이 보통 추론의 몇 배 메모리 필요

한 문장 정의 — 파인튜닝은 모델을 가르치는 과정이라, 그냥 돌릴 때보다 훨씬 더 많은 메모리가 필요하고, 이 메모리 부족이 가장 큰 걸림돌이다.

왜 학습이 더 많이 먹나 — 비유로

모델을 돌릴 때는 입력 → 출력, 한 방향만 계산한다(순방향).

가르칠 때는 한 번 더 한다. "어디서 틀렸지?"를 거꾸로 따라가며 손잡이를 고친다(역방향, 역전파).

이 거꾸로 가는 과정에서 손잡이마다 추가 메모(그래디언트·옵티마이저 스테이트)를 들고 있어야 한다.

그래서 학습 가능한 손잡이가 많을수록 메모리가 더 든다.

# 추론: 한 방향만
# `output`에 중간 결과를 담아 다음 줄에서 재사용합니다.
output = forward(input)

# 학습: 한 번 더, 거꾸로 (메모리 더 듦)
# `output`에 중간 결과를 담아 다음 줄에서 재사용합니다.
output = forward(input)
backward(output, answer)  # 손잡이마다 메모 들고 고침

예시 1 — 추론 메모리 어림 계산 (worked example)

손잡이 130억 개 모델, 숫자 1개당 2칸(바이트)이라 하자.

가중치: 130억 × 2칸 = 26GB.

여기에 부수적인 것 약 20%를 더하면 → 약 31GB.

추론 메모리 ≈ (손잡이 수 × 칸 수) × 1.2
            ≈ 26GB × 1.2 = 31.2GB

예시 2 — 학습 메모리는 더 크다 (부분 완성)

같은 130억 모델을 통째로 가르치면, 손잡이마다 메모 3개씩 더 든다.

130억 × 3 × 2칸 = 78GB가 추가로 필요하다.

만약 손잡이를 10억 개만 가르친다면 추가 메모리는 ____ 로 확 준다.

(빈칸 답: 10억 × 3 × 2 = 6GB. 손잡이를 적게 가르칠수록 메모리가 준다.)

예시 3 — 메모리 아끼는 잔기술 (독립 적용)

활성화라는 중간 계산값을 저장하면 메모리를 또 많이 먹는다.

저장하는 대신 필요할 때마다 다시 계산하면 메모리는 줄지만 시간이 더 걸린다.

이걸 그래디언트 체크포인팅(활성화 재계산)이라 한다.

"공간을 아끼려고 시간을 더 쓰는" 맞바꿈이다.

핵심 통찰 — 학습 가능한 손잡이가 많을수록 메모리가 늘어난다. 그러니 손잡이를 적게 돌리면 메모리가 준다. 이게 바로 다음에 나올 PEFT의 핵심 아이디어다.


개념 3 — 양자화: 숫자 자릿수를 줄여 공간 아끼기

망가지는 장면

"모델은 24GB 칩에 겨우 올렸는데, 더 큰 모델은 도저히 안 올라간다."

일상비유

장부에 숫자를 적을 때 3.141592653까지 다 적으면 칸이 많이 든다.

3.14로 줄여 적으면 칸이 확 준다. 살짝 부정확해도 대부분 괜찮다.

모델 안 숫자도 똑같이 줄여 적을 수 있다. 이게 양자화다.

비유 코드 위험
3.141592 → 3.14 (반올림) load(bits=16) 살짝 부정확
더 거칠게 반올림 load(bits=4) 너무 줄이면 답 품질 떨어짐

한 문장 정의 — 양자화는 숫자 하나를 표현하는 자릿수(비트)를 줄여 모델의 메모리 사용량을 줄이는, 싸고 효과적인 방법이다.

자릿수 종류 — 많이 쓰는 것만

형식 자릿수(비트) 한 줄 특징
FP32 32 가장 정확, 가장 많은 공간
FP16 / BF16 16 절반 공간, 학습에 흔함
INT8 8 더 작게, 추론에 흔함
INT4 / NF4 4 가장 작게, 소비자 GPU 학습용

자릿수를 절반으로 줄이면 모델 공간도 절반으로 준다.

예시 1 — 자릿수와 공간 (worked example)

손잡이 100억 개 모델.

32칸 형식이면 가중치에 40GB.

16칸 형식으로 바꾸면 → 20GB. 절반이다.

# 아래 예제는 핵심 흐름만 짧게 보여 줍니다.
load_model(bits=32)  # 40GB
load_model(bits=16)  # 20GB (절반)

예시 2 — 형식을 잘못 고르면 (부분 완성)

라마 2는 BF16이라는 형식으로 공개됐다.

많은 팀이 무심코 FP16으로 불러왔다.

둘 다 16칸인데 나누는 방식이 달라서, 모델 품질이 광고보다 ____ 떨어졌다.

(빈칸 답: 크게. 교훈 — 모델은 반드시 지정된 형식으로 불러와야 한다.)

예시 3 — 언제 줄이나 (독립 적용)

가장 흔한 방식은 학습이 다 끝난 뒤 줄이는 것이다(PTQ, 학습 후 양자화).

코드 몇 줄이면 되고, 모델을 직접 안 만드는 앱 개발자에게 딱 맞다.

학습 중에 줄이는 방식(QAT)도 있는데, 품질은 더 좋지만 학습이 느려진다.

처음이라면 PTQ로 충분하다.

한 걸음 더 ▸ (지금 몰라도 됨)

자릿수를 어디까지 줄일 수 있을까? 이론상 1비트가 최소다. 마이크로소프트의 BitNet b1.58은 1.58비트만으로도 어느 규모까지는 16비트 라마 2와 비슷한 성능을 냈다. 애플은 기기에서 모델을 돌리려고 평균 3.5비트짜리 혼합 방식을 쓰기도 했다. 지금은 "자릿수 줄이면 공간 준다"만 알면 된다.


개념 4 — PEFT와 LoRA: 손잡이를 다 안 돌리기

망가지는 장면

"70억짜리 모델 하나 통째로 가르치려니 56GB가 필요하다. 내 GPU는 24GB뿐인데."

일상비유

옷이 좀 안 맞는다고 옷을 처음부터 다시 짜지 않는다.

소매 길이만 살짝 줄인다. 손이 훨씬 덜 간다.

모델도 손잡이 1,000억 개를 다 돌리지 않고, 아주 일부만 돌려도 비슷한 효과를 낸다.

이렇게 일부만 돌리는 방법을 통틀어 PEFT라 한다.

비유 코드 위험
옷 전체 다시 짜기(전체 파인튜닝) finetune(all_params) → 56GB 메모리 폭발
소매만 수선(PEFT) finetune(method="LoRA") → 적게 전체만큼 완벽하진 않을 수 있음

한 문장 정의 — PEFT는 모델의 손잡이 전부가 아니라 극히 일부만 학습해, 적은 메모리로 전체 파인튜닝에 가까운 성능을 내는 방법이다.

LoRA — 가장 인기 있는 PEFT

PEFT 중 가장 널리 쓰이는 게 LoRA다 (0장에 없으니 여기서 설명).

LoRA의 아이디어는 이렇다.

손잡이 한 덩어리(큰 표)를 통째로 바꾸는 대신, 작은 표 두 개를 곁에 붙여 그것만 돌린다.

다 가르친 뒤엔 원래 표에 합쳐 버린다.

# 큰 표 W는 그대로 두고, 작은 표 A·B만 학습
# 다 끝나면 W에 합침 → 돌릴 때 느려지지 않음
# 모델을 조금 더 가르치거나 학습 설정을 준비합니다.
finetune(method="LoRA", rank=8)

왜 작은 표 두 개로 충분한가 — 비유

9칸×9칸짜리 큰 표는 81개 숫자가 든다.

이걸 9칸×1, 1칸×9 두 줄로 쪼개면 18개면 된다.

77% 줄었다. 살짝 정보는 잃지만 대부분 쓸 만하다.

거대 모델은 겉보기와 달리 "실제로 중요한 손잡이는 적다"는 성질이 있어서, 이 방식이 잘 통한다.

예시 1 — LoRA가 얼마나 적게 돌리나 (worked example)

아주 큰 모델(원서 인용: 1,750억 손잡이)을 LoRA로 가르칠 때,

전체의 단 0.0027%인 약 470만 개만 돌리고도 비슷하거나 더 나은 성능을 냈다.

거의 안 건드리고도 된다는 뜻이다.

예시 2 — 옛 방식과 LoRA 차이 (부분 완성)

LoRA 이전 어댑터 방식은 모델 사이사이에 새 부품을 끼웠다.

그래서 모델을 돌릴 때마다 그 부품을 거쳐야 해서 ____ 느려졌다.

LoRA는 다 가르친 뒤 원래 표에 합쳐 버린다 → 돌릴 때 추가 부품이 없다.

(빈칸 답: 추론이. LoRA는 합쳐 버리니 추론이 느려지지 않는다.)

예시 3 — QLoRA: 양자화까지 더하기 (독립 적용)

LoRA에 양자화(개념 3)를 합치면 어떻게 될까?

그게 QLoRA다. 모델 가중치를 4칸으로 줄여 들고 있다가, 계산할 때만 잠깐 늘려 쓴다.

덕분에 650억짜리 큰 모델도 48GB GPU 하나로 가르칠 수 있게 됐다.

"손잡이 일부만(LoRA) + 자릿수 줄여서(양자화)" 두 기술의 합작이다.

미니 시나리오 — 고객마다 다른 모델 서빙하기

고객 100명에게 각자 맞춤 모델을 줘야 한다.

LoRA를 쓰면, 큰 모델 1개는 공유하고 고객마다 작은 표(어댑터)만 따로 둔다.

100명분 모델을 통째로 저장하는 것보다 공간이 수십 배 절약된다.

고객을 바꿀 때도 작은 표만 갈아 끼우면 돼서 빠르다.

한 걸음 더 ▸ (지금 몰라도 됨)

LoRA를 어디에 적용할지(어떤 손잡이 묶음), 작은 표를 얼마나 작게 할지(랭크)는 실험으로 정한다. 보통 랭크는 4~64면 충분하다. 또 여러 모델을 아예 합쳐서 하나로 만드는 모델 병합이라는 기법도 있다. 서로 다른 강점의 모델을 평균 내거나 레이어를 쌓아 합친다. 지금은 "손잡이 일부만 돌린다 = LoRA"만 기억하면 된다.


정리

핵심 3줄.

  1. 모델이 사실을 몰라 틀리면 RAG, 형식·버릇이 틀리면 파인튜닝.
  2. 파인튜닝의 가장 큰 벽은 메모리다. 학습은 추론보다 훨씬 많이 먹는다.
  3. 메모리를 줄이는 두 길 — 숫자 자릿수를 줄이거나(양자화), 손잡이를 일부만 돌린다(PEFT·LoRA).

단순 규칙: 사실은 RAG, 형식은 파인튜닝. 그리고 파인튜닝은 메모리부터 걱정하라.


더 해보기

검증된 공식 자료 (생존 확인 2026-05-21).


다음 8장에서는 파인튜닝에 꼭 필요한 "좋은 데이터를 어떻게 모으나"를 다룬다. 지금은 "사실은 RAG, 형식은 파인튜닝, 메모리가 벽"만 머리에 있으면 충분하다.


연습문제

  1. 설명. 모델을 살짝 더 가르치기의 핵심을 처음 듣는 사람에게 한 문장으로 설명하라.
  2. 구분. 두 개념(RAG, 파인튜닝)을 실제 예시 하나로 구분하라.
  3. 적용. 내 프로젝트나 학습 노트에서 이 장의 개념을 적용해 작게 개선할 지점을 하나 고르라.

부록 A. 쉬운 용어 사전

용어 아주 쉬운 뜻 이 장에서 나온 위치
RAG 답변할 때 관련 자료를 찾아 붙여 모델이 근거를 보고 답하게 하는 방식. 부록 B와 본문 예시
파인튜닝 이미 학습된 모델에 새 예시를 더 보여 주어 특정 행동을 더 잘하게 만드는 작업. 부록 B와 본문 예시
양자화 모델 숫자의 자릿수를 줄여 메모리와 계산 비용을 낮추는 방법. 부록 B와 본문 예시
LoRA 모델 전체가 아니라 작은 추가 부품만 학습해 비용을 줄이는 파인튜닝 방식. 부록 B와 본문 예시

부록 B. 헷갈리는 개념 비교표

A B 구분 포인트
RAG 파인튜닝 RAG는 지식 부족에 좋고, 파인튜닝은 행동 방식 보정에 더 가깝다.
양자화 LoRA 양자화는 숫자 크기를 줄이고, LoRA는 작은 학습 부품을 붙인다.

부록 C. 더 읽을 자료

  • 이 장의 더 해보기 섹션 — 이미 모아 둔 공식 문서나 실습 링크가 있으면 여기서 먼저 확인한다.
  • 같은 책의 0장 한눈에 보기 — 용어가 막히면 0장의 용어집과 개념 척추로 돌아간다.
  • 원본 딥다이브판 같은 장 — 입문판을 읽고 큰 흐름이 잡힌 뒤 세부 논리를 더 깊게 확인한다.
  • 이 장의 flashcards.json — 읽은 직후 질문만 보고 답을 떠올리는 회상 연습에 쓴다.

부록 D. 연습문제 풀이

  1. 설명 예시. 모델을 살짝 더 가르치기는 거대 모델을 제품에 넣을 때 어떤 선택을 하고 어떻게 확인할지 판단하게 해 주는 장이다. 중요한 것은 용어를 외우는 것이 아니라, 이 개념이 어떤 입력·부품·결정에 영향을 주는지 말로 풀어 보는 것이다.
  2. 구분 예시. 두 개념(RAG, 파인튜닝)의 차이는 이렇게 잡으면 된다. RAG는 지식 부족에 좋고, 파인튜닝은 행동 방식 보정에 더 가깝다. 실제 사례를 볼 때는 목적, 입력, 실패했을 때의 증상을 따로 적어 보면 헷갈리지 않는다.
  3. 적용 예시. 가장 작은 개선부터 고른다. 예를 들어 이름을 더 분명히 하거나, 평가 기준을 한 줄 추가하거나, 직접 알 필요 없는 내부 정보를 감추는 식으로 시작한다. 한 번에 크게 갈아엎는 것보다 작은 변경 하나를 확인하며 진행하는 쪽이 입문 단계에 맞다.
난이도
에피소드
질문
카드를 로딩 중...
답변

클릭하거나 Space를 눌러 뒤집기

0 / 0
학습 진도 0%
이동   Space 뒤집기   R 셔플